#include <iostream>
#include <functional>
#include <vector>
#include <memory>
#include <unordered_map>
#include <unistd.h>
#include <cstdint>

// 定时任务的描述
using TaskFunc = std::function<void()>;    // 定时任务函数
using TaskRelease = std::function<void()>; // 移除任务id 与 weak_ptr 关联的函数
class TimeTask
{
private:
    uint64_t _tid;        // 定时任务的id
    bool _cancel;         // 取消定时任务
    uint32_t _timeout;    // 定时任务的超时时间
    TaskFunc _task_cb;    // 超时时要执行的任务
    TaskRelease _release; // 用于删除uid与weak_ptr的映射关系

public:
    TimeTask(uint64_t id, uint32_t timeout, const TaskFunc &cb)
        : _tid(id), _timeout(timeout), _task_cb(cb)
    {
    }

    ~TimeTask()
    {
        // 对象销毁时，执行定时任务
        if (_cancel == false) // false代表任务没有被取消，true表示任务被取消
        {
            _task_cb();
        }
        _release();
    }

    void Cancel()
    {
        _cancel = true;
    }

    void SetRelease(const TaskRelease &cb)
    {
        _release = cb;
    }

    uint32_t GetTimeOut()
    {
        return _timeout;
    }
};

// 时间轮执行定时任务
using TaskPtr = std::shared_ptr<TimeTask>;
using WeakPtr = std::weak_ptr<TimeTask>; // shared_ptr需要交给weak_ptr去维护
class TimeWheel
{
private:
    int _tick;                                    // 这个像指针，指向什么位置，任务超时被执行
    int _capacity;                                // 表示时间轮的最大延迟时间
    std::unordered_map<uint64_t, WeakPtr> _timer; // 存储的是任务id,和weak_ptr的映射
    std::vector<std::vector<TaskPtr> > _wheel;    // 时间轮中存储的是任务的智能指针
private:
    void RemoveTimer(uint64_t id)
    {
        auto it = _timer.find(id);
        if (it != _timer.end())
        {
            _timer.erase(id);
        }
    }

public:
    TimeWheel() : _tick(0), _capacity(60), _wheel(_capacity)
    {
    }

    // 添加定时任务    延迟时间
    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb)
    {
        TaskPtr pt(new TimeTask(id, delay, cb));
        pt->SetRelease(std::bind(&TimeWheel::RemoveTimer, this, id));
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
        _timer[id] = WeakPtr(pt);
    }

    // 刷新 / 延长定时任务
    void TimerRefresh(uint64_t id)
    {
        // 从id与weak_ptr的映射中获取到weak_ptr,再通过weak_ptr构造出shared_ptr对象
        auto it = _timer.find(id);
        if (it == _timer.end())
        {
            return;
        }

        TaskPtr pt = it->second.lock(); // lock就是从weak_ptr中获取shared_ptr对象
        int delay = pt->GetTimeOut();
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
    }

    void TimerCancel(uint64_t id)
    {
        auto it = _timer.find(id);
        if (it == _timer.end())
        {
            return;
        }

        TaskPtr pt = it->second.lock();
        if (pt)
        {
            pt->Cancel();
        }
    }

    // _tick位置必须每秒走一步
    void RunTaskTick()
    {
        _tick = (_tick + 1) % _capacity;
        // 将数组中通过shared_ptr保存的任务进行释放
        _wheel[_tick].clear();
    }
};

class Test
{
public:
    Test()
    {
        std::cout << "构造函数 ~~~" << std::endl;
    }

    ~Test()
    {
        std::cout << "析构函数 ~~~" << std::endl;
    }
};

void Delete(Test *t)
{
    delete t;
}

int main()
{
    TimeWheel tw;
    Test *t = new Test;
    tw.TimerAdd(100, 5, std::bind(Delete, t));
    for (int i = 0; i < 5; i++)
    {
        sleep(1);
        // 刷新一下定时任务
        tw.TimerRefresh(100);
        tw.RunTaskTick();
        std::cout << " 任务刷新成功,在5秒后执行!" << std::endl;
    }

    tw.TimerCancel(100);
    while (1)
    {
        sleep(1);
        std::cout << " ------------------------- " << std::endl;
        tw.RunTaskTick();
    }
    return 0;
}